4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 namespace Microsoft
.JScript
{
18 using Microsoft
.JScript
.Vsa
;
20 using System
.Reflection
;
23 public class ArrayPrototype
: ArrayObject
{
24 internal static readonly ArrayPrototype ob
= new ArrayPrototype(ObjectPrototype
.ob
);
25 internal static ArrayConstructor _constructor
;
27 internal ArrayPrototype(ObjectPrototype parent
)
29 this.noExpando
= true;
32 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasVarArgs
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.Array_concat
)]
33 public static ArrayObject
concat(Object thisob
, VsaEngine engine
, params Object
[] args
){
34 ArrayObject arrayObj
= engine
.GetOriginalArrayConstructor().Construct();
35 if (thisob
is ArrayObject
)
36 arrayObj
.Concat((ArrayObject
)thisob
);
38 arrayObj
.Concat(thisob
);
39 for (int i
= 0; i
< args
.Length
; i
++){
41 if (arg
is ArrayObject
)
42 arrayObj
.Concat((ArrayObject
)arg
);
49 public static ArrayConstructor constructor
{
51 return ArrayPrototype
._constructor
;
55 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_join
)]
56 public static String
join(Object thisob
, Object separator
){
57 if (separator
is Missing
)
58 return Join(thisob
, ",", false);
60 return Join(thisob
, Convert
.ToString(separator
), false);
63 internal static String
Join(Object thisob
, String separator
, bool localize
){
64 StringBuilder str
= new StringBuilder();
65 uint thisLength
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
66 if (thisLength
> int.MaxValue
)
67 throw new JScriptException(JSError
.OutOfMemory
);
68 // Small optimization so we're not doing a bunch of reallocs for large arrays.
69 if (thisLength
> str
.Capacity
)
70 str
.Capacity
= (int)thisLength
;
71 for (uint i
= 0; i
< thisLength
; i
++){
72 Object
value = LateBinding
.GetValueAtIndex(thisob
, i
);
73 if (value != null && !(value is Missing
)){
75 str
.Append(Convert
.ToLocaleString(value));
77 str
.Append(Convert
.ToString(value));
80 str
.Append(separator
);
82 return str
.ToString();
85 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_pop
)]
86 public static Object
pop(Object thisob
){
87 uint thisLength
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
89 LateBinding
.SetMemberValue(thisob
, "length", 0);
92 Object result
= LateBinding
.GetValueAtIndex(thisob
, thisLength
-1);
93 LateBinding
.DeleteValueAtIndex(thisob
, thisLength
-1);
94 LateBinding
.SetMemberValue(thisob
, "length", thisLength
-1);
98 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasVarArgs
, JSBuiltin
.Array_push
)]
99 public static long push(Object thisob
, params Object
[] args
){
100 uint length
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
101 for (uint i
= 0; i
< args
.Length
; i
++)
102 LateBinding
.SetValueAtIndex(thisob
, i
+(ulong)length
, args
[i
]);
103 long newLength
= length
+args
.Length
;
104 LateBinding
.SetMemberValue(thisob
, "length", newLength
);
108 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_reverse
)]
109 public static Object
reverse(Object thisob
){
110 uint thisLength
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
111 uint halfSize
= thisLength
/2;
112 for (uint low
= 0, high
= thisLength
- 1; low
< halfSize
; low
++, high
--)
113 LateBinding
.SwapValues(thisob
, low
, high
);
117 internal override void SetMemberValue(String name
, Object
value){
118 if (this.noExpando
) //This the fast prototype
119 throw new JScriptException(JSError
.OLENoPropOrMethod
);
120 base.SetMemberValue(name
, value);
123 internal override void SetValueAtIndex(uint index
, Object
value){
124 if (this.noExpando
) //This the fast prototype
125 throw new JScriptException(JSError
.OLENoPropOrMethod
);
126 base.SetValueAtIndex(index
, value);
129 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_shift
)]
130 public static Object
shift(Object thisob
){
132 if (thisob
is ArrayObject
)
133 return ((ArrayObject
)thisob
).Shift();
134 uint length
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
136 LateBinding
.SetMemberValue(thisob
, "length", 0);
139 res
= LateBinding
.GetValueAtIndex(thisob
, 0);
140 for (uint i
= 1; i
< length
; i
++){
141 Object val
= LateBinding
.GetValueAtIndex(thisob
, i
);
143 LateBinding
.DeleteValueAtIndex(thisob
, i
-1);
145 LateBinding
.SetValueAtIndex(thisob
, i
-1, val
);
147 LateBinding
.DeleteValueAtIndex(thisob
, length
-1);
148 LateBinding
.SetMemberValue(thisob
, "length", length
-1);
152 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.Array_slice
)]
153 public static ArrayObject
slice(Object thisob
, VsaEngine engine
, double start
, Object end
){
154 ArrayObject array
= engine
.GetOriginalArrayConstructor().Construct();
155 uint length
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
156 // compute the start index
157 long startIndex
= Runtime
.DoubleToInt64(Convert
.ToInteger(start
));
159 startIndex
= length
+ startIndex
;
162 }else if (startIndex
> length
)
164 // compute the end index
165 long endIndex
= length
;
166 if (end
!= null && !(end
is Missing
)){
167 endIndex
= Runtime
.DoubleToInt64(Convert
.ToInteger(end
));
169 endIndex
= length
+ endIndex
;
172 }else if (endIndex
> length
)
176 if (endIndex
> startIndex
){
177 array
.length
= endIndex
- startIndex
;
178 for (ulong i
= (ulong)startIndex
, j
= 0; i
< (ulong)endIndex
; i
++, j
++){
179 Object val
= LateBinding
.GetValueAtIndex(thisob
, i
);
180 if (!(val
is Missing
))
181 LateBinding
.SetValueAtIndex(array
, j
, val
);
187 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_sort
)]
188 public static Object
sort(Object thisob
, Object function
){
189 ScriptFunction func
= null;
190 if (function
is ScriptFunction
)
191 func
= (ScriptFunction
)function
;
192 uint length
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
193 if (thisob
is ArrayObject
)
194 ((ArrayObject
)thisob
).Sort(func
);
195 else if (length
<= Int32
.MaxValue
){
196 QuickSort qs
= new QuickSort(thisob
, func
);
197 qs
.SortObject(0, length
);
202 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasVarArgs
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.Array_splice
)]
203 public static ArrayObject
splice(Object thisob
, VsaEngine engine
, double start
, double deleteCnt
, params Object
[] args
){
204 uint oldLength
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
205 // compute the start index
206 long startIndex
= Runtime
.DoubleToInt64(Convert
.ToInteger(start
));
208 startIndex
= oldLength
+ startIndex
;
211 }else if (startIndex
> oldLength
)
212 startIndex
= oldLength
;
214 // compute the number of items to delete
215 long deleteCount
= Runtime
.DoubleToInt64(Convert
.ToInteger(deleteCnt
));
218 else if (deleteCount
> oldLength
- startIndex
)
219 deleteCount
= oldLength
- startIndex
;
220 long newLength
= oldLength
+ args
.Length
- deleteCount
;
222 // create an array for the result
223 ArrayObject result
= engine
.GetOriginalArrayConstructor().Construct();
224 result
.length
= deleteCount
;
226 // special case array objects (nice speedup if dense)
227 if (thisob
is ArrayObject
){
228 ((ArrayObject
)thisob
).Splice((uint)startIndex
, (uint)deleteCount
, args
, result
, (uint)oldLength
, (uint)newLength
);
232 // copy the deleted items to the result array
233 for (ulong i
= 0; i
< (ulong)deleteCount
; i
++)
234 result
.SetValueAtIndex((uint)i
, LateBinding
.GetValueAtIndex(thisob
, i
+(ulong)startIndex
));
236 // shift the remaining elements left or right
237 long n
= oldLength
-startIndex
-deleteCount
;
238 if (newLength
< oldLength
){
239 for (long i
= 0; i
< n
; i
++)
240 LateBinding
.SetValueAtIndex(thisob
, (ulong)(i
+startIndex
+args
.Length
), LateBinding
.GetValueAtIndex(thisob
, (ulong)(i
+startIndex
+deleteCount
)));
241 LateBinding
.SetMemberValue(thisob
, "length", newLength
);
243 LateBinding
.SetMemberValue(thisob
, "length", newLength
);
244 for (long i
= n
-1; i
>= 0; i
--)
245 LateBinding
.SetValueAtIndex(thisob
, (ulong)(i
+startIndex
+args
.Length
), LateBinding
.GetValueAtIndex(thisob
, (ulong)(i
+startIndex
+deleteCount
)));
248 // splice in the arguments
249 int m
= args
== null ? 0 : args
.Length
;
250 for (uint i
= 0; i
< m
; i
++)
251 LateBinding
.SetValueAtIndex(thisob
, i
+(ulong)startIndex
, args
[i
]);
256 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_toLocaleString
)]
257 public static String
toLocaleString(Object thisob
){
258 if (thisob
is ArrayObject
){
259 StringBuilder sep
= new StringBuilder(System
.Globalization
.CultureInfo
.CurrentCulture
.TextInfo
.ListSeparator
);
260 if (sep
[sep
.Length
-1] != ' ')
262 return ArrayPrototype
.Join(thisob
, sep
.ToString(), true);
264 throw new JScriptException(JSError
.NeedArrayObject
);
267 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.Array_toString
)]
268 public static String
toString(Object thisob
){
269 if (thisob
is ArrayObject
)
270 return ArrayPrototype
.Join(thisob
, ",", false);
271 throw new JScriptException(JSError
.NeedArrayObject
);
274 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasVarArgs
, JSBuiltin
.Array_unshift
)]
275 public static Object
unshift(Object thisob
, params Object
[] args
){
276 if (args
== null || args
.Length
== 0) return thisob
;
277 if (thisob
is ArrayObject
)
278 return ((ArrayObject
)thisob
).Unshift(args
);
279 uint oldLength
= Convert
.ToUint32(LateBinding
.GetMemberValue(thisob
, "length"));
280 long newLength
= oldLength
+ args
.Length
;
281 LateBinding
.SetMemberValue(thisob
, "length", newLength
);
283 for (long i
= oldLength
- 1; i
>= 0; i
--){
284 Object val
= LateBinding
.GetValueAtIndex(thisob
, (ulong)i
);
286 LateBinding
.DeleteValueAtIndex(thisob
, (ulong)(i
+ args
.Length
));
288 LateBinding
.SetValueAtIndex(thisob
, (ulong)(i
+ args
.Length
), val
);
290 // copy the input args
291 for (uint i
= 0; i
< args
.Length
; i
++)
292 LateBinding
.SetValueAtIndex(thisob
, i
, args
[i
]);